import 'dart:io';
import 'package:chameleonultragui/connector/serial_abstract.dart';
import 'package:chameleonultragui/gui/menu/pages/logs_viewer.dart';
import 'package:chameleonultragui/helpers/definitions.dart';
import 'package:chameleonultragui/helpers/flash.dart';
import 'package:chameleonultragui/helpers/general.dart';
import 'package:chameleonultragui/recovery/recovery.dart';
import 'package:chameleonultragui/main.dart';
import 'package:file_picker/file_picker.dart';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter/services.dart';
// Recovery
import 'package:chameleonultragui/recovery/recovery.dart' as recovery;

// Localizations
import 'package:chameleonultragui/generated/i18n/app_localizations.dart';

class DebugPage extends StatelessWidget {
  // Home Page
  const DebugPage({super.key});

  @override
  Widget build(BuildContext context) {
    var appState = context.watch<ChameleonGUIState>();
    var localizations = AppLocalizations.of(context)!;
    return Scaffold(
        appBar: AppBar(
          title: const Text('🐞'),
        ),
        body: SingleChildScrollView(
            child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Align(
                alignment: Alignment.topRight,
                child: IconButton(
                  onPressed: () {
                    // Disconnect
                    appState.connector!.performDisconnect();
                    appState.changesMade();
                  },
                  icon: const Icon(Icons.close),
                ),
              ),
              const Text(
                '🐞 Chameleon Ultra GUI DEBUG MENU 🐞',
                textScaler: TextScaler.linear(2),
              ),
              Text(
                localizations.debug_page_warning,
                textScaler: const TextScaler.linear(2),
              ),
              Text('⚠️ ${localizations.warned} ⚠️',
                  textScaler: const TextScaler.linear(3)),
              Text('${localizations.platform}: ${Platform.operatingSystem}'),
              Text('${localizations.serial_protocol}: ${appState.connector}'),
              Text(
                  '${localizations.chameleon_connected}: ${appState.connector!.connected}'),
              Text(
                  '${localizations.chameleon_device_type}: ${appState.connector!.device}'),
              Text(
                  '${localizations.shared_preferences_logging}: ${appState.sharedPreferencesProvider.isDebugLogging()} with ${appState.sharedPreferencesProvider.getLogLines().length} lines'),
              const SizedBox(height: 10),
              Text(localizations.production_logging,
                  textScaler: const TextScaler.linear(1.5)),
              const SizedBox(height: 5),
              Text(localizations.slow_down_warning,
                  textScaler: const TextScaler.linear(0.9)),
              const SizedBox(height: 10),
              if (!appState.sharedPreferencesProvider.isDebugLogging())
                ElevatedButton(
                  onPressed: () async {
                    appState.sharedPreferencesProvider.setDebugLogging(true);
                    await appState.connector!.performDisconnect();
                    appState.log = null;
                    appState.connector = null;
                    appState.changesMade();
                  },
                  child: Column(children: [
                    Text(localizations.enable_production_logging),
                  ]),
                ),
              if (appState.sharedPreferencesProvider.isDebugLogging())
                ElevatedButton(
                  onPressed: () async {
                    appState.sharedPreferencesProvider.setDebugLogging(false);
                    await appState.connector!.performDisconnect();
                    appState.log = null;
                    appState.connector = null;
                    appState.changesMade();
                  },
                  child: Column(children: [
                    Text(localizations.disable_production_logging),
                  ]),
                ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  appState.sharedPreferencesProvider.clearLogLines();
                  appState.changesMade();
                },
                child: Column(children: [
                  Text(localizations.clear_logs),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await Clipboard.setData(ClipboardData(
                      text: appState.sharedPreferencesProvider
                          .getLogLines()
                          .join("\n")));
                },
                child: Column(children: [
                  Text(localizations.copy_logs_to_clipboard),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  try {
                    await FileSaver.instance.saveAs(
                        name:
                            "log${DateTime.now().toIso8601String().replaceAll(':', '-')}",
                        bytes: Uint8List.fromList(appState
                            .sharedPreferencesProvider
                            .getLogLines()
                            .join("\n")
                            .codeUnits),
                        ext: 'txt',
                        mimeType: MimeType.text);
                  } on UnimplementedError catch (_) {
                    String? outputFile = await FilePicker.platform.saveFile(
                      dialogTitle: '${localizations.output_file}:',
                      fileName:
                          'log${DateTime.now().toIso8601String().replaceAll(':', '-')}.txt',
                    );

                    if (outputFile != null) {
                      var file = File(outputFile);
                      await file.writeAsBytes(Uint8List.fromList(appState
                          .sharedPreferencesProvider
                          .getLogLines()
                          .join("\n")
                          .codeUnits));
                    }
                  }
                },
                child: Column(children: [
                  Text(localizations.export_logs_to_file),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => const LogsViewerPage(),
                    ),
                  );
                },
                child: Column(children: [
                  Text(localizations.logs),
                ]),
              ),
              const SizedBox(height: 10),
              Text(localizations.recovery_library,
                  textScaler: const TextScaler.linear(1.5)),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await appState.communicator!.setReaderDeviceMode(true);
                  var distance = await appState.communicator!.getMf1NTDistance(
                      50,
                      0x60,
                      Uint8List.fromList([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));
                  bool found = false;
                  for (var i = 0; i < 0xFF && !found; i++) {
                    var nonces = await appState.communicator!
                        .getMf1NestedNonces(
                            50,
                            0x60,
                            Uint8List.fromList(
                                [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]),
                            0,
                            0x61);
                    var nested = NestedDart(
                        uid: distance.uid,
                        distance: distance.distance,
                        nt0: nonces.nonces[0].nt,
                        nt0Enc: nonces.nonces[0].ntEnc,
                        par0: nonces.nonces[0].parity,
                        nt1: nonces.nonces[1].nt,
                        nt1Enc: nonces.nonces[1].ntEnc,
                        par1: nonces.nonces[1].parity);

                    var keys = await recovery.nested(nested);
                    if (keys.isNotEmpty) {
                      appState.log!.d("Found keys: $keys. Checking them...");
                      for (var key in keys) {
                        var keyBytes = u64ToBytes(key);
                        if ((await appState.communicator!
                                .mf1Auth(0x03, 0x61, keyBytes.sublist(2, 8))) ==
                            true) {
                          appState.log!.i(
                              "Found valid key! Key ${bytesToHex(keyBytes.sublist(2, 8))}");
                          found = true;
                          break;
                        }
                      }
                    } else {
                      appState.log!.d("Can't find keys, retrying...");
                    }
                  }
                },
                child: Column(children: [
                  Text(localizations.nested_attack),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await appState.communicator!.setReaderDeviceMode(true);
                  var distance = await appState.communicator!.getMf1NTDistance(
                      50,
                      0x60,
                      Uint8List.fromList([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]));
                  bool found = false;
                  for (var i = 0; i < 0xFF && !found; i++) {
                    var nonces = await appState.communicator!
                        .getMf1NestedNonces(
                            50,
                            0x60,
                            Uint8List.fromList(
                                [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]),
                            0,
                            0x61,
                            level: NTLevel.weak);
                    var nested = StaticNestedDart(
                        uid: distance.uid,
                        keyType: 0x61,
                        nt0: nonces.nonces[0].nt,
                        nt0Enc: nonces.nonces[0].ntEnc,
                        nt1: nonces.nonces[1].nt,
                        nt1Enc: nonces.nonces[1].ntEnc);

                    var keys = await recovery.staticNested(nested);
                    if (keys.isNotEmpty) {
                      appState.log!.d("Found keys: $keys. Checking them...");
                      for (var key in keys) {
                        var keyBytes = u64ToBytes(key);
                        if ((await appState.communicator!
                                .mf1Auth(0x03, 0x61, keyBytes.sublist(2, 8))) ==
                            true) {
                          appState.log!.i(
                              "Found valid key! Key ${bytesToHex(keyBytes.sublist(2, 8))}");
                          found = true;
                          break;
                        }
                      }
                    } else {
                      appState.log!.d("Can't find keys, retrying...");
                    }
                  }
                },
                child: Column(children: [
                  Text(localizations.static_nested_attack),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await appState.communicator!.setReaderDeviceMode(true);
                  var data = await appState.communicator!
                      .getMf1Darkside(0x03, 0x61, true, 15);
                  var darkside = DarksideDart(uid: data.uid, items: []);
                  bool found = false;

                  for (var tries = 0; tries < 0xFF && !found; tries++) {
                    darkside.items.add(DarksideItemDart(
                        nt1: data.nt1,
                        ks1: data.ks1,
                        par: data.par,
                        nr: data.nr,
                        ar: data.ar));
                    var keys = await recovery.darkside(darkside);
                    if (keys.isNotEmpty) {
                      appState.log!.d("Found keys: $keys. Checking them...");
                      for (var key in keys) {
                        var keyBytes = u64ToBytes(key);
                        if ((await appState.communicator!
                                .mf1Auth(0x03, 0x61, keyBytes.sublist(2, 8))) ==
                            true) {
                          appState.log!.i(
                              "Found valid key! Key ${bytesToHex(keyBytes.sublist(2, 8))}");
                          found = true;
                          break;
                        }
                      }
                    } else {
                      appState.log!.d("Can't find keys, retrying...");
                      data = await appState.communicator!
                          .getMf1Darkside(0x03, 0x61, false, 15);
                    }
                  }
                },
                child: Column(children: [
                  Text(localizations.darkside_attack),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  var darkside = DarksideDart(uid: 2374329723, items: []);
                  darkside.items.add(DarksideItemDart(
                      nt1: 913032415,
                      ks1: 216745674933338888,
                      par: 0,
                      nr: 0,
                      ar: 0));
                  darkside.items.add(DarksideItemDart(
                      nt1: 913032415,
                      ks1: 1010230244403446283,
                      par: 0,
                      nr: 1,
                      ar: 0));
                  var keys = await recovery.darkside(darkside);
                  appState.log!.d("Darkside output: $keys");

                  if (context.mounted) {
                    showDialog<String>(
                      context: context,
                      builder: (BuildContext context) => AlertDialog(
                        title: Text(localizations.debug_mode),
                        content: Text(
                            "Self test: valid key exists in list ${keys.contains(0xFFFFFFFFFFFF)}"),
                        actions: <Widget>[
                          TextButton(
                            onPressed: () => Navigator.pop(context),
                            child: Text(localizations.ok),
                          ),
                        ],
                      ),
                    );
                  }
                },
                child: Column(children: [
                  Text(localizations.test_darkside_lib),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  var nested = NestedDart(
                      uid: 2374329723,
                      distance: 613,
                      nt0: 1999585272,
                      nt0Enc: 3173333529,
                      par0: 3,
                      nt1: 128306861,
                      nt1Enc: 2363514210,
                      par1: 7);
                  var keys = await recovery.nested(nested);
                  appState.log!.d("Nested output: $keys");

                  if (context.mounted) {
                    showDialog<String>(
                      context: context,
                      builder: (BuildContext context) => AlertDialog(
                        title: Text(localizations.debug_mode),
                        content: Text(
                            "Self test: valid key exists in list ${keys.contains(0xFFFFFFFFFFFF)}"),
                        actions: <Widget>[
                          TextButton(
                            onPressed: () => Navigator.pop(context),
                            child: Text(localizations.ok),
                          ),
                        ],
                      ),
                    );
                  }
                },
                child: Column(children: [
                  Text(localizations.test_nested_lib),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  var nested = HardNestedDart(
                      nonces: hexToBytes(
                          '41a56e2600017da88a97ce29023bb43c57ec307bc61cc86ee24bb334f24ca0bfe060088516a7f6e905c7baea628092b49e56f719f83ec684c426e8e93461edcc44eef1e7bafab9d68ce05635e54d3d5b90a4b1ef4773494c236adc0ccebf9e6a7f10b45f404c2dee171686ef59f1cbbacc26ae7eb40a09b5b7ae60b9b3e615f64f2a060fcc7e59132b785fcbada80486a228ed9b42818ba917a174f1980da5c919693c19d7eabb1a8314a1ff0d6ce39c39fcf53e926d55d04f3115a51e04b025552a0dc020281dbf27e15af076950dd27aee2e13639058ba9e008c1383eca5be504e073c2be6f04398c25293183a796b7e710f43a2bd30a57258c5893aeec04b043f1b2c7283b9a9a2f954ee664fb3020c99a4e6516d4f989240f570a1171ce92a6e1c94f9ed8bc8cb62bab2de93be941de4ff416839761094d519b95ebcfd204511bf96cc8273b26448ccad73d82f1327e7e0d41187263ac049a6cf2ba36d4c813b54abab07e41d717bba45b73b6a03df617c6a21d0af3f039063f65bc3528d02fb68afbe8969775e4cce56537bf9a4e67c8c761f6c2a05f12a51ee541a8115666fb190ca05acd65fec1ae689d82012317fa82135c21d3c854abbab13851cb0aef002a0d834f0d598b566861404962e283f55fb6c88026347eba5a13f370e945d6fe66e3aa25ada90ea3cf2d8566cadd408efaefaeef74c6e90d7e500a811eb620810e999f53606a1323afa9bc32ee31208fc9e270f1420ed013a24e91669a18ed536813226f51b02d58eea113d36e69c8d90d293664665f06ddfe8d663e2132ebed790cef986cb3e5cfd9d353c60526d4cdf716c65015845fc5cd39bdb1d0640bd2d86c7f0a824668473654b887066157c50f17ffcd973514b4f0262199be8417725bd25e749253c8ea56e6afb658abc06d2867431ac1fd9c74f12b7e2a37e12e3851ad7744b8effc14ed891e030ccdf3f448bb5bf7861ada1a10b64188025ee3914f7a2f6bb4b529f8121439c49b4faaca4a164d4404ad52eb70b465c1f6508466b28fc6defe04e99cfc13f210eb5bbac29a46244e1894e485192a7bdff2586bd8d75a9806a25a5485302ca4d08eae9d84735c7ffffe1b78bc856619bfa636f487b05556e4ddf2ca940e8570f79f01deaa34c03fd04d81a9693bca149b1b04ff9c1051f4d7fc9b9e4401b50d9d66a91a41738ed48181e3e38fb44da04db3a811aac9495037518fb950ce1160c3c0b937a0e41507e35e0cc599459dd46265686457325133509b0954d12eb92677fae2436b1e5639453fe150a6f3491cb9cfaa9e0c65649b21bb81040f3c093e7533f026cf305f1838ee4ca857b015f0491ec6726c93b458f995c03fc66448f2af1ff8946a610798451f9008ade0b6f04f306a7c8c3980d334797e7566bdcd861e43f5144d7a873497e18d53d1726dda74b879d265242221a39fd544ba9089051a9f53daf0d70e2e7f286db8ab628a9e88a10bff966d18bf73feef205c488ae2c8839db639fc8385b15331c343efa57fb4a45800a8e0dc59e0fa49254efeb543efc2c5a53a120169d2be1c48c5dda4859483f0f20629bd2b1083d7cf356f61eea528b9bf6dbcbdf6b2b98a9d480efcf6efbd8daf6d8b5719b4b78b5d95bd5d6ff481e824569069378608bbfdb93cc7b847ff848efabbe269aad9b0e3ddfe0481d552639bedbbc0b6f262e950ca981a26d7f6d724d9b1a5b7a5cbb43951961be64b9ea868165544bcf1992c734c59620d7043d74b1a449816a5d4d3de0682416c4dc16d48194c817c589450fc728d196e980e51156cdb419e2d006b37f461eb4910076cf861900f970d34d59cf8fe933ed08d06b6be5647772e06819a0f5ab1f1bb6859221475099fd24b9ecf313d659ded5462bcd187f0873772f18c1790342d698b6d9cc034af90307062cbea6dee4eabeca61c619804d399d5c70470e5c367cac9e52f49b644cbb6324011a93adaecd69fb9d0880b1a300592d07667517a98f921aaf3c7190498bebed096d2a9692cab7b75f1d07e102f4fbcd91b0f87de7a0693d94c5d161078cc773206364946eadfc9d4fff2412c8e638f7e2c58045bc4e2f6e5b2d328951b0b675fef7798138e986f6eda8e081f8c2357e9464a355f84a6df71b57e6b74e6d01eec3a84094aa395bc43e07d22391d0674996f7d164e366c70bbd5e55f45cb20fc4369fbc3225e404913fbb48649ae637723066d4ebba4aa0f530768eef54419283c6b10b2c12b77ffd818af6b3b2f3a473bf0a55d9a70f0a3276ee9096a7986814c4c34e35071fe1afc2f0a889e7e6547219ab1a8c0bc356aafa462f62a1181824d4e5ba9602a7b468d7f88b97891dec4a6783b32c04f4c12d362df0d2088cd62db786b5d1d8354727003c0286840fcdf1dfab6ccd821fbd10c02004f042ccf1c80474f9b5a3b46fe2f0d6c93667a17ce6febd1e7f6ba69ecacc0a37beb446afed76c136221071d8d435b5a5b84527d77cd038d61f331a705885a510352541a958357443d7e92b2f2e05b33a1549981a47e390f939e228d103cba5da43bf22802ad0bd3aeaa9a9ed6c0a5df05a9f9056f5971cb3bc6708b3f20411eef3c27c0e1aad29f407e86854aedbf4f4553df619332d3a8d6f1980c9ab1d320fc03e6240a27f7dd26e488518582f790927b4c9536e91513964ea3a7e8f4b2c642ed38f0d6ddbd9ed9374007c28a93bbf0e61dcc8ad604d22622fa8232a26305e3376838e13f8617e2496163fe784ff014f5aecfdaf517a1d2c790a5a8d8af4bf14ce74368472d40b1357296588bff1d9e8a99881a513a1af094a6fc859cf4ecc30eb776cb085ddbac1fa2e59c786b3f045a905d3a2b06c8dc3a68c01288e543cddc7914b31c11a86fd037f47174c2d05bef1d42bab64f80928cbf64fac00c451183146ad881011a2fccbbb65b4407a804254274039857ce7c87489ff1bae6c5f80fb1eaccfdfa1761db423b5238eaa229345c0f32997532a3dd5ff146dd59e3abee46b30971fd6888bc8198a3dc5fef09781c64d5d719ebd64cbe5a37504edbc332619cdd2e96e00499ba6bdc37639156f1311e08a6a923ce860be80788ae7515cd10f9ba5e8cb51887c6e99ed96c4c7ab0f3c6f1ae12b9a50e8f2cd75e62425f726d7cc90be59cacb30a15e77c8f75e5e95d6677817224891c571f4549706a14cf492c92722f729bfc94ded98e913cd4be933942e6f9e827a51efb33731bc7611f872534e83378d0686d02c4949977bbc3e64c5f7df5c9ac4207d1de47a390e4c5379fa8405757a9f1372979bf748c5afe5383234e1fb9ccec0c5fc4052edd7479d858737ce0170822c7997bf58fa15a6f7c3674dffa02a2841b158665842837e6d7967eb76cb89dea2a20fff1f01e7136c682237559d953db1755799faa14efbfa31a37feb669ad3439dae1c51ed6e00dcae07512a32d1ab265ca43373c7650cd8f489406f17dddc3096d40fef3b1b4f1a553cd08c498913b2ee1e0f1b688d5fd7123dbf86ef3f32af4c58d927f9e396bbfa592a36a171c04fdd90ccc88a6b97675103ced4f8e15eefec4d9579c13295a73b61445c4b2aa18474a983ea420289e5631e8fe0e4802d0bf56ed036fc326aeb0979237adf26ba1135d22ed730ebb46e451c3e1662509ae56e93c9b9294faab4c084de37b1f0ed1de1d1c3cdaa83607d2b41acbb8fe0d82fb8fca5d1a81f33bbcc4ad3879e03611f07caf8d7eaf879749c179bc4d47f277754f9ff98a9836df64445ba6cbd28e406ee901e95620b04ed65de29e7ef8596ed2b105aa173fe9054fcdad833ac69733c5aeadd7e1a083505af33e19be32bee1b4cb07055d3a282b9e25a463153c42c13c7c3bd0530500dfc7c321e73b265f5d26f5e6d70f091d382d0d20578815537bbad504a2f13503f5adc3a3614018235993d8ee27464ea4291267edd99fe27c5f03bfd99220afb1c4c080b507e4216c0bd3d2edc52a48d9c0d2a43f50f9b8256868f76bd6578e0af260c3cb1b07dabbc40ac339584f4699dd50235052bc9fa85e80b738f750cb2ec99bfb30f81a5e6aa2fb88e80dfd89314ba0b2255de641296f95ecce8cdda4407e41cc420769bb3e94d5da1d9750a0f9cdad1b25585ae9caaef9877a66cd0885fe9cc3e0402df9895122b7e028c8131d2b20b69f15478a36c61b61e7234007af3c18687b4b36127762e48e1e3b6a6031a07b0d7be5150300814b091b46c9f00b5e0efb0111460fbc321239838268ab0f8452b4e9254a2178577b7c468502318465093e8dae0611e573db41e87adbf0c7dc3f5f8f8b13031316e98c2389e88bfe7aea08d1c4be6198f2765af954cd18829c74de798218e5e15b430e697774b651caebb4033d690bc1cd39aeef45b65de75ddc2a9a9067bb31061b2e0c25216c51aab3b0bf460110313f25cdd10400ca8a99b29688cccf9abf80007237fd547cc943c6de2947e64dcdf733ae45414ea8b9951d997ee0df01d0dec2b164471227730b9699289bb196e64398aa0ac8d2e801842434d90a061f91e2a65e1a51f38fdec24ec52aa82ceeb84d316fce502ef1b4f16ecddd7560689ed90ee2e0b451d32d9cdd3155d74ac873d0bfeaad4f266dd285afdaa5d1ef8c2166b6a698dc3d9436ef1906c1af50857b57f069bd44ca8894848b9a05121d1a94aab7068281a3e88fe4b0db44009a6ef7fab0bf7ab3f6efaa170d0bd7625c204b8ec5af6a75c62cb480f5e89a07f41d0f343bfda16aea9004b427f6953f21b593912553fe62ccfcee1cab92b21c976d9a89f007c95f670ac657396e7a37ab820e8aaacf1977fd03282730530d9219e64c7b17ca011635cebf8cb541a1d2606b1b4a7f576d0a04401a0376d394c773b5b7d0bf7db4119287e1a75368f97096334a51120aac0c13d2420727630a5b319358097bf5f31400558dc83cc193588ac449375824983937e9f06ca32a0917e6b6bb27efe2d06486ba6ed5e985bf343521b53fa73f9f07bf624840e4bb34c56f2946278202c33b33c4d31779b2d88290667d1cb9c004bd399ed477730ba87f959abd43bf935133db84de0490974cc5596a975fef0dfbf3ce7e142eb6afd363fab0eaff28c2244956c1b49266c94bb9039ec4da050112bb44f35c1e1eca9cbf92abfc25f2d915589804609f1232992bf79f0005ee907f3864476e40750418f69ce61122e87c6cdd526a2730de9a29da4e94361cfd7c7d62616a884d2d310901e3bc64517242bfefb52925a2f98d657084c5658b18e5ce800b9dc15a993752e0e84cee1e34014942d07ad984745a3d5ae446be6d07e93cda62109d60d2e8ec7d2a567fcf32b155cafa6f3cfcee11c0d419e6c83386448b023e47a7a6f12c06f55ddf60be44c76f06c88a31483c43b9606a85752500de9bec92837c6b9a87644766d4249718f35c8af81759cbcff543ae85d6b84be3caf1ad7f2e084ca3e276d20bfaafc01ee251648942c03819c6e9da3719dcc8c12c2b66922474536bd9b5b311ecf0af9ac5292bbf796b8dc41ac140084ba21cff3a0f6b16e104e39214e847fc9134b7ccc731f0c9c20e2dbfb6aa25932f0e3f3aef713dcff1948b6b798ae779ba8f655b50939b2b17a6113d5604a6c26950de7e4e55b762c75d43c045e82151e5f71023e1078cc8988f2f134c2ea1cc9c3647ece7cb687bfc0a29cfb74ebee89f720fa426c02231a0b5726b6d83d19fa7a99ca1ca4d6b7e7d8367d30165d40c6980ca1f222e2474914e276f656c7d3eb72773ba28246ab6ab97f984034ef891cbb12ea3f16716cb2ca48e04951e838738b1dc6d05218fd412ad4604d12fb4931b83784000d2008e2553cb70e636869c0bd753d8e5ba7ccee305a1eb99d77db9bebfcebb00b6bb9e0d43277ececb52fd152a0b5acfc69035b9b2b0a1db6c4dc5bb57f19e945235ccbd3d9ffef411ee2c3f37663635c579ebededa366f6f87f7ceaf0e80852037d4fe916eaaceafb760f2dede1985bd1648df3d6dea19b069ade3466caaf24ba8375737fe274a0017b2a17e48928eb6da1c703f27eeebcbf338162493c2b07667ee7fcccb4f0c01b36262ff7a1591eda45e321a24d98e7549c4f99a8fc6799cad424eddce26784e2acc84d1d9aba89bb2a6fe006a05d42099bd49dce1f458b7c39546812085b3c20afe24af28a6e4247da2f1d047cd131c7086aabaf2734978a583e6b6e457201bf51e81e17cd818af5915f0e519e4a9f3e035d661423f3f1ffb420b2e32d2bc60eb8e9589f8305fafff9f6f58caf0a928f774d52445aa9e6170b5ed47242922ad2c075318f77771bdf3330f83c253da401b71ceeb4d416e198c4116baa54b970b2a756ca8819496fa0a040c9b5c10aa1e81b0d616050f806a46dc950fed46711e668f4bc2abf5097068ac97f916e0cf828078f708dc2427c84876cb3e9355624f3561577b2cbbe39ad97c6f0ba5c9ab0a5c93c5a7fbcefa0e2c302150e745c68c1392f7e5f232db3d4db38da7460c2f2b983f6877608e63fc37f0ee615db7fafd0c322e363eb1af1b2573a1f894d00e1972e5b1f72aa8bef41b5c4e494aad70e9286ee3e7d182993bb30aae807912751cd9d942d30993dec7cb22e2294baef67b4e7f4133ae7ed509e43790f2df1517404d8363fad3a968e5556c7cb048e0d83a974f30e1d62ba2eec187e26ebe59dfc24d5276c5a529d1173568b5cfca13ee7bb588f4ad613d5456117a90bd93b5082ea9ee186c3963fa30351ae9750d27c03bfa33aef9c517996c3d8aabd678d84dd4ce2c00a684e8d00472addda1eb826a7ec3dde404af0b0f5b55b8433d779614415d116eaf3a20ff328f2047bdcb95015fbf12b128ac7b4245207ade68655098e00f2bd451f3b097407a019758c809da61080d3f10a3a4dd495f97fb7cef184275440346244f9916a385d51bb90d6b00a9c9ba4a866751b984adfb0ef0cc8574ea7c7d6eb37feffd6758b55bbbfc02e845b414a55a7bf954392e0347da71f70ad4c0a3b5369f9956cd6cf8ef0bf44aa644c07cdfcfc09fbf95102b9d64cb4ebf5d9d56ac370934d8fbb362cf9ad48e2354275f212970e21247d7faaf3746ec7d65a8aaf01f997a77d6aff2b3d26ffb5c966d2c991f957b7aa7b573a729113f359dd55acaa27c6082e5621a3aab2355631e4421b791684c263491f311133ce61619d96d3636e19966ecc5d195eae0c097b25b58e388fc10c5d241a31bbd9c29fe5b1361dccf45d110f13d11a013b0929422fbc730f2bdf8057b6a684306e13be80bb1c5fc47a0007c26f60808b81306778ba2e269481b03a2a5db4b69230bc3edabeccbfb43b2e3748b110914c6e7474c1d206bbae0cf530319dcb57e44a8781f3f0a566ef1b4bcf7aed2fc661df90518067ebfe82dca30811e73cab6be30680d794fb486c3949135182286e19d803739ef23e2651cdb66b8b9d6568ed08425a403cdc684b406af0a0acbfd3ee4539d571ecd0f0bcc1ad1d7a6c528be0fa6ed1046758931a5241d9389725943086b19a5c0b4046b5fd185fe0e6769b5571af91433806a6a4453f5ebda079a62ed93610fd719c8bf051b262f7f6477978318acc270912825241352aa11cd5f42408326d0ddfc25381d64b7cca6a0f23ef1d6c27b86d28925268ae2b51b3cc08dda9a206f5123d885ecd017d6cf332b0cad1db8f9270fd3aef843b1bbc0624d0d18236f3a8cb02d81e72ae2907204e49fa2221074fdae5513557119a5a484b5db67c3edad77e0db3ef69d87258d0f8617633648b376da3b46a27cd2de25e22bf5f2d1bc9687720cfd306f521d85d6e71f9cc78c8903cefec4f344f9946a8ea20b330a965439ae33edf8b42e2935d94cd0865577509108648d458f2f611a2a98e894ba96e0f74a6f190695465ec854d7d222697fb263d4b4f7ec68b6fdb564d77996c8f7778dc6e5aa630816dea109bc20931fa287d235dc62bed323959bf1c169c35dd66cd838857cba1a424ab308b82822612769cefcc23ac0e4aeeccf226b8b80ec4d9feffd33adcee3916231b0a2b1f76367faeb108fb37611b97211c4881c181fdbe74dc778d47e4bbc8e3f10edb3655c57f1d5b4f4371774ade85fe4100711ac5cf69ea53fb923cae140dadc8ff34582fb74a5732dbd669a4d3247fbe03eadc2d4280851f10c3667e79c3aa0297366b25c43212eedb1e1105ba47f9cf94643488beeeee1427bc9b391d10513d2211a80a017f42c2012b14fc76566a1d7bc96b96f9ef4f6a75f478cf058e7e580d623774848903bb44c9b81c55ddf4f021dcac6f2aa1998664c0332db4d4d843b403966f66153aaf2a4fff421227381381a2e6d9fafb80e9329f6156c1dda02be975479481666b6319921dee103fa65ca0dfc1d8e534db48fea2cbb042b50f3c3b9fcca719216109424'));
                  var keys = await recovery.hardNested(nested);
                  appState.log!.d("HardNested output: $keys");
                  appState.log!.d(
                      "Self test: valid key exists in list ${keys.contains(0xFBF225DC5D58)}");

                  if (context.mounted) {
                    showDialog<String>(
                      context: context,
                      builder: (BuildContext context) => AlertDialog(
                        title: Text(localizations.debug_mode),
                        content: Text(
                            "Self test: valid key exists in list ${keys.contains(0xFBF225DC5D58)}"),
                        actions: <Widget>[
                          TextButton(
                            onPressed: () => Navigator.pop(context),
                            child: Text(localizations.ok),
                          ),
                        ],
                      ),
                    );
                  }
                },
                child: Column(children: [
                  Text("${localizations.test_nested_lib} (hard)"),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  var nested = StaticEncryptedNestedDart(
                      uid: 0x72000003,
                      nt: 0x82d91e42,
                      ntEnc: 0x98b90e04,
                      ntParEnc: 1011);
                  var keys = await recovery.staticEncryptedNested(nested);
                  appState.log!
                      .d("Nested output: ${keys.length} possible keys");

                  if (context.mounted) {
                    showDialog<String>(
                      context: context,
                      builder: (BuildContext context) => AlertDialog(
                        title: Text(localizations.debug_mode),
                        content: Text(
                            "Self test: valid key exists in list ${keys.contains(0x55654483DA14)}"),
                        actions: <Widget>[
                          TextButton(
                            onPressed: () => Navigator.pop(context),
                            child: Text(localizations.ok),
                          ),
                        ],
                      ),
                    );
                  }
                },
                child: Column(children: [
                  Text("${localizations.test_nested_lib} (static encrypted)"),
                ]),
              ),
              const SizedBox(height: 10),
              Text(localizations.force_flashing,
                  textScaler: const TextScaler.linear(1.5)),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await flashFirmware(appState,
                      device: ChameleonDevice.ultra,
                      enterDFU: appState.connector!.connected);
                },
                child: Column(children: [
                  Text('💀 ${localizations.dfu_flash_ultra} 💀'),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await flashFirmware(appState,
                      device: ChameleonDevice.lite,
                      enterDFU: appState.connector!.connected);
                },
                child: Column(children: [
                  Text('💀 ${localizations.dfu_flash_lite} 💀'),
                ]),
              ),
              const SizedBox(height: 10),
              Text(localizations.other,
                  textScaler: const TextScaler.linear(1.5)),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await appState.communicator!.factoryReset();
                },
                child: Column(children: [
                  Text(
                      '✅ ${localizations.safe_option}: ${localizations.restart_chameleon} ✅'),
                ]),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () async {
                  await appState.communicator!.setReaderDeviceMode(true);
                  var card = await appState.communicator!.scan14443aTag();
                  if (card != null) {
                    appState.log!.d('Card UID: ${card.uid}');
                    appState.log!.d('SAK: ${card.sak}');
                    appState.log!.d('ATQA: ${card.atqa}');
                    await appState.communicator!.setReaderDeviceMode(false);
                    await appState.communicator!.setMf1AntiCollision(card);
                  }
                },
                child: Column(children: [
                  Text(localizations.copy_uid),
                ]),
              ),
              const SizedBox(height: 10),
            ],
          ),
        )));
  }
}
